package com.woniuxy.service.impl;

import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.extension.api.R;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.hash.BloomFilter;
import com.woniuxy.anno.BloomFilterAnnotation;
import com.woniuxy.entity.PowerUser;
import com.woniuxy.entity.PowerUserAndRole;
import com.woniuxy.entity.dto.PowerUserDTO;
import com.woniuxy.entity.dto.YiDTO;
import com.woniuxy.mapper.PowerUserMapper;
import com.woniuxy.service.PowerUserService;
import com.woniuxy.util.*;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @program: tsm
 * @description:
 * @create: 2024-10-16 21:24
 **/
@Service
public class PowerUserServiceImpl implements PowerUserService {
    @Autowired
    private PowerUserMapper powerUserMapper;
    @Autowired
    private StringRedisTemplate redisTemplateInit;
    @Autowired
    private BloomFilter<String> bloomFilter; // 注入布隆过滤器
    @Value("${login.salt}")
    private String salt;
    private Set<String> loggedOutUsers = new HashSet<>();//注销用户集合

    /**
     * 重置密码
     *
     * @param username
     * @param password
     * @return
     */
    @Override
    public ResponseData<?> resetPassword(String username, String password) {
        String s = SecureUtil.md5(password + salt);
        int result = powerUserMapper.updatePassword(username, s);
        if (result > 0) {
            return new ResponseData<>().ok();
        }
        return new ResponseData<>().fail(ResponseEnum.ERROR_PASSWORD);
    }

    /**
     * 登录方法
     * 施加了防止重复登录的功能
     *
     * @param powerUser
     * @return
     */
    @SneakyThrows
    @Override
    public ResponseData<?> login(PowerUser powerUser) {
        //1、用前端密码对比数据库密码
        //校验用户合法性,加密对比
        //密码加上盐值后再加密(md5(123+qwer))
        PowerUser userinfo = powerUserMapper.queryPowerUser(powerUser);

        if (userinfo == null) {
            return new ResponseData<>().fail(ResponseEnum.LOGIN_ERROR);
        }


        // 在此处检查用户是否已经在布隆过滤器中
        String userId = String.valueOf(userinfo.getId()); // 获取用户 ID

        if (BloomFilterUtil.checkInBloomFilter(userId, bloomFilter) && !loggedOutUsers.contains(userId)) {
            return new ResponseData<>().fail(ResponseEnum.ALREADY_LOGGED_IN); // 如果用户已经登录
        }



        String md5pw = SecureUtil.md5(powerUser.getPassword() + salt);
        if (!userinfo.getPassword().equals(md5pw)) {
            return new ResponseData<>().fail(ResponseEnum.LOGIN_ERROR);
        }


        // 2. 检查 Redis 中是否已经存在有效 JWT，防止重复登录
        String redisKey = "jwt:" + userinfo.getId();
        String existingJwt = (String) redisTemplateInit.opsForValue().get(redisKey);

        if (existingJwt != null) {
            // 如果存在有效的 JWT，表示用户已经登录
            return new ResponseData<>().fail(ResponseEnum.ALREADY_LOGGED_IN);  // 返回一个用户已登录的错误信息
        }


        //2、产生一个jwt（用户凭证）
        Map map = new HashMap<>();
        map.put("id", userinfo.getId());
        map.put("username", userinfo.getUsername());
        String jwt = JwtUtil.createJWT(map);

        //3、把jwt放入redis
        //redis：采用key-val存储的数据库，mysql:表格，mangodb：json
        redisTemplateInit.opsForValue().set("jwt:" + userinfo.getId(), jwt, 60, TimeUnit.MINUTES);

        //将用户 ID 添加到布隆过滤器
        BloomFilterUtil.addToBloomFilter(userId, bloomFilter);

        Map resultMap = new HashMap();
        resultMap.put("jwt", jwt);
        resultMap.put("userInfo", userinfo);

        return new ResponseData<>().ok(resultMap);
    }

    /**
     * 退出登录
     * 清空redis里的jwt
     * 注意前端清楚localStorage的内容
     *
     * @param powerUser
     * @return
     */
    @Override
    public ResponseData<?> SignOut(PowerUser powerUser) {
        PowerUser userinfo = powerUserMapper.queryPowerUser(powerUser);
        //  检查 Redis 中是否已经存在有效 JWT，防止重复登录
        String redisKey = "jwt:" + userinfo.getId();
        String existingJwt = (String) redisTemplateInit.opsForValue().get(redisKey);
        if (existingJwt == null) {
            return new ResponseData<>().fail(ResponseEnum.JWT_TIMEOUT);  // jwt已经过期
        }
        // 从 Redis 中删除存储的 JWT
        redisTemplateInit.delete(redisKey);

        loggedOutUsers.add(String.valueOf(userinfo.getId()));//注销用户集合

        return new ResponseData<>().ok();
    }

    /**
     * 个人资料查询和修改
     *
     * @param id
     * @return
     */
    @Override
    public ResponseData<?> queryById(Integer id) {
        return new ResponseData<>().ok(powerUserMapper.queryPowerUserById(id));
    }

    @Override
    public ResponseData<?> updatePerson(PowerUser powerUser) {
        return new ResponseData<>().ok(powerUserMapper.updatePerson(powerUser));
    }

    /**
     * 更新头像
     *
     * @param id
     * @param imgSrc
     * @return
     */
    @Override
    public ResponseData<?> updateImg(Integer id, String imgSrc) {
        return new ResponseData<>().ok(powerUserMapper.updateImg(id, imgSrc));
    }

    /**
     * 分页查员工管理
     *
     * @param pageData
     * @return
     */
    @Override
    public ResponseData<?> queryAllPowerUser(PageData<PowerUserDTO> pageData) {
        PageHelper.startPage(pageData.getPageNum(), pageData.getPageSize());
        List<PowerUserDTO> powerUser = powerUserMapper.queryAllPowerUser(pageData.getParam());
        PageInfo pageInfo = new PageInfo(powerUser);
        return new ResponseData<>().ok(pageInfo);
    }

    /**
     * 删除员工（修改员工状态）
     *
     * @param id
     * @return
     */
    @Override
    public ResponseData<?> updateStatus(Integer id) {
        return new ResponseData<>().ok(powerUserMapper.updateStatus(id));
    }

    /**
     * 添加方法且分配角色
     */
    @Override
    public ResponseData<?> addPowerUser(PowerUserDTO powerUserDTO) {

        PowerUser powerUser = new PowerUser(powerUserDTO);
        powerUser.setCreatedId(UserContext.getUserId().intValue());
        String s = SecureUtil.md5(powerUserDTO.getPassword() + salt);
        powerUser.setPassword(s);
        powerUserMapper.add(powerUser);


        PowerUserAndRole powerUserAndRole = new PowerUserAndRole();

        powerUserAndRole.setRoleId(powerUserDTO.getRoleId());
        powerUserAndRole.setPoweruserId(powerUser.getId());
        powerUserMapper.addByRole(powerUserAndRole);


        return new ResponseData<>().ok();
    }

    /**
     * 查菜单权限表
     * @param poweruserId
     * @return
     */
    @Override
    public ResponseData<?> queryPower(Integer poweruserId) {
        return new ResponseData<>().ok(powerUserMapper.queryPower(poweruserId));
    }

    /**
     * 修改菜单权限
     * @param powerUserDTO
     * @return
     */
    @Override
    public ResponseData<?> updatePower(Integer roleId, Integer poweruserId) {
        return new ResponseData<>().ok(powerUserMapper.updatePower(roleId,poweruserId));
    }
}